﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Globalization;
using System.Security;

namespace PickGold
{
	/// <summary>
	/// 十六进制编码集
	/// </summary>
	[Serializable]
	[ComVisible(true)]
	public class HexEncoding : Encoding
	{
		/// <summary>
		/// Hex
		/// </summary>
		public static readonly HexEncoding Hex = new HexEncoding();

		/// <summary>
		/// 计算对指定字符数组中的一组字符进行编码所产生的字节数。
		/// </summary>
		/// <param name="chars">包含要编码的字符集的字符数组。</param>
		/// <param name="index">第一个要编码的字符的索引。</param>
		/// <param name="count">要编码的字符的数目。</param>
		/// <returns>对指定字符进行编码后生成的字节数。</returns>
		/// <exception cref="System.ArgumentNullException">chars 为 null。</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">index 或 count 小于零。- 或 -index 和 count 不表示 chars 中的有效范围。</exception>
		/// <exception cref="System.Text.EncoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.EncoderFallback 设置为 System.Text.EncoderExceptionFallback。</exception>
		public override int GetByteCount(char[] chars, int index, int count)
		{
			if (chars == null || chars.Length == 0)
				return 0;

			if (index < 0)
				index = 0;
			if (count > chars.Length - index)
				count = chars.Length - index;
			return (count + 1) / 2;
		}

		/// <summary>
		/// 将指定字符数组中的一组字符编码为指定的字节数组。
		/// </summary>
		/// <param name="chars">包含要编码的字符集的字符数组。</param>
		/// <param name="charIndex">第一个要编码的字符的索引。</param>
		/// <param name="charCount">要编码的字符的数目。</param>
		/// <param name="bytes">要包含所产生的字节序列的字节数组。</param>
		/// <param name="byteIndex">开始写入所产生的字节序列的索引位置。</param>
		/// <returns>写入 bytes 的实际字节数。</returns>
		/// <exception cref="System.ArgumentNullException">chars 为 null。- 或 -bytes 为 null。</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">charIndex、charCount 或 byteIndex 小于零。- 或 -charIndex 和 charCount 不表示 chars 中的有效范围。- 或 -byteIndex 不是 bytes 中的有效索引。</exception>
		/// <exception cref="System.ArgumentException">bytes 中从 byteIndex 到数组结尾没有足够的容量来容纳所产生的字节。</exception>
		/// <exception cref="System.Text.EncoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.EncoderFallback </exception>
		public override int GetBytes(char[] chars, int charIndex, int charCount, byte[] bytes, int byteIndex)
		{
			if (chars == null || chars.Length == 0)
				return 0;

			if (charIndex < 0)
				charIndex = 0;
			if (charCount > chars.Length - charIndex)
				charCount = chars.Length - charIndex;
			var v = byteIndex;
			for (var i = 0; i < charCount; i += 2)
				bytes[v++] = byte.Parse(new string(chars, i, 2), NumberStyles.HexNumber);
			return v - byteIndex;
		}

		/// <summary>
		/// 计算对字节序列（从指定字节数组开始）进行解码所产生的字符数。
		/// </summary>
		/// <param name="bytes">包含要解码的字节序列的字节数组。</param>
		/// <param name="index">第一个要解码的字节的索引。</param>
		/// <param name="count">要解码的字节数。</param>
		/// <returns>对指定字节序列进行解码所产生的字符数。</returns>
		/// <exception cref="System.ArgumentNullException">bytes 为 null。</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">index 或 count 小于零。- 或 -index 和 count 不表示 bytes 中的有效范围。</exception>
		/// <exception cref="System.Text.DecoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.DecoderFallback 设置为 System.Text.DecoderExceptionFallback。</exception>
		public override int GetCharCount(byte[] bytes, int index, int count)
		{
			if (bytes == null || bytes.Length == 0)
				return 0;

			if (index < 0)
				index = 0;
			if (count > bytes.Length - index)
				count = bytes.Length - index;
			return count * 2;
		}

		/// <summary>
		/// 将指定字节数组中的字节序列解码为指定的字符数组。
		/// </summary>
		/// <param name="bytes">包含要解码的字节序列的字节数组。</param>
		/// <param name="byteIndex">第一个要解码的字节的索引。</param>
		/// <param name="byteCount">要解码的字节数。</param>
		/// <param name="chars">要用于包含所产生的字符集的字符数组。</param>
		/// <param name="charIndex">开始写入所产生的字符集的索引位置。</param>
		/// <returns>写入 chars 的实际字符数。</returns>
		/// <exception cref="System.ArgumentNullException">bytes 为 null。- 或 -chars 为 null。</exception>
		/// <exception cref="System.ArgumentOutOfRangeException">byteIndex、byteCount 或 charIndex 小于零。- 或 -byteindex 和 byteCount 不表示 bytes 中的有效范围。- 或 -charIndex 不是 chars 中的有效索引。</exception>
		/// <exception cref="System.ArgumentException">chars 中从 charIndex 到数组结尾没有足够容量来容纳所产生的字符。</exception>
		/// <exception cref="System.Text.DecoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.DecoderFallback 设置为 System.Text.DecoderExceptionFallback。</exception>
		public override int GetChars(byte[] bytes, int byteIndex, int byteCount, char[] chars, int charIndex)
		{
			if (bytes == null || bytes.Length == 0)
				return 0;

			if (byteIndex < 0)
				byteIndex = 0;
			if (byteCount > bytes.Length - byteIndex)
				byteCount = bytes.Length - byteIndex;
			var v = charIndex;
			for (var i = 0; i < byteCount; i++)
			{
				var t = bytes[i].ToString("X2");
				chars[v++] = t[0];
				chars[v++] = t[1];
			}
			return v - charIndex;
		}

		/// <summary>
		/// 计算对指定数目的字符进行编码所产生的最大字节数。
		/// </summary>
		/// <param name="charCount">要编码的字符的数目。</param>
		/// <returns>对指定数目的字符进行编码所产生的最大字节数。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException">charCount 小于零。</exception>
		/// <exception cref="System.Text.EncoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.EncoderFallback 设置为 System.Text.EncoderExceptionFallback。</exception>
		public override int GetMaxByteCount(int charCount)
		{
			return (charCount + 1) / 2;
		}

		/// <summary>
		/// 计算对指定数目的字节进行解码时所产生的最大字符数。
		/// </summary>
		/// <param name="byteCount">要解码的字节数。</param>
		/// <returns>对指定数目的字节进行解码时所产生的最大字符数。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException">byteCount 小于零。</exception>
		/// <exception cref="System.Text.DecoderFallbackException">发生回退（请参见Understanding Encodings以获得完整的解释）－和－System.Text.Encoding.DecoderFallback 设置为 System.Text.DecoderExceptionFallback。</exception>
		public override int GetMaxCharCount(int byteCount)
		{
			return byteCount * 2;
		}

		/// <summary>
		/// 获取可与邮件代理正文标记一起使用的当前编码的名称。
		/// </summary>
		public override string BodyName
		{
			get
			{
				return "hex";
			}
		}

		/// <summary>
		/// 获取当前 System.Text.Encoding 的代码页标识符。
		/// </summary>
		public override int CodePage
		{
			get
			{
				return 1981;
			}
		}

		/// <summary>
		/// 获取当前编码的可读说明。
		/// </summary>
		public override string EncodingName
		{
			get
			{
				return "HEX";
			}
		}

		/// <summary>
		/// 获取一个值，该值指示浏览器客户端是否可以使用当前的编码显示内容。
		/// </summary>
		public override bool IsBrowserDisplay
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// 获取一个值，该值指示浏览器客户端是否可以使用当前的编码保存内容。
		/// </summary>
		public override bool IsBrowserSave
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// 获取一个值，该值指示邮件和新闻客户端是否可以使用当前的编码显示内容。
		/// </summary>
		public override bool IsMailNewsDisplay
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// 获取一个值，该值指示邮件和新闻客户端是否可以使用当前的编码保存内容。
		/// </summary>
		public override bool IsMailNewsSave
		{
			get
			{
				return false;
			}
		}

		/// <summary>
		/// 获取一个值，该值指示当前的编码是否使用单字节码位。
		/// </summary>
		public override bool IsSingleByte
		{
			get
			{
				return true;
			}
		}

		/// <summary>
		/// 获取可与邮件代理标题标记一起使用的当前编码的名称。
		/// </summary>
		public override string HeaderName
		{
			get
			{
				return "hex";
			}
		}

		/// <summary>
		/// 获取在 Internet 编号分配管理机构 (IANA) 注册的当前编码的名称。
		/// </summary>
		public override string WebName
		{
			get
			{
				return "HEX";
			}
		}

		/// <summary>
		/// 获取与当前编码最紧密对应的 Windows 操作系统代码页。
		/// </summary>
		public override int WindowsCodePage
		{
			get
			{
				return 1981;
			}
		}

		/// <summary>
		/// 将 Unicode 字符数组（它将二进制数据编码为 Base64 数字）的子集转换为等效的 8 位无符号整数数组。参数指定输入数组的子集以及要转换的元素数。
		/// </summary>
		/// <param name="input">Unicode 字符数组。</param>
		/// <param name="offset"><paramref name="input"/> 内的一个位置。</param>
		/// <param name="length">要转换的 <paramref name="input"/> 中的元素数。</param>
		/// <returns>等效于 <paramref name="input"/> 中位于 offset 位置的 length 元素的 8 位无符号整数数组。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException">offset 或 length 小于 0。- 或 -offset 和 length 指示不在 <paramref name="input"/> 内的位置。</exception>
		/// <exception cref="System.FormatException"><paramref name="input"/> 的长度（忽略空白字符）不是 0 或 4 的倍数。- 或 -<paramref name="input"/> 的格式无效。<paramref name="input"/> 包含一个非 base 64 字符、两个以上的填充字符或者在填充字符中包含非空白字符。</exception>
		[SecuritySafeCritical]
		public static byte[] FromBase64CharArray(char[] input, int offset, int length)
		{
			if (input == null)
				return null;

			if (length < offset)
				length = input.Length;
			return System.Convert.FromBase64CharArray(input, offset, length);
		}
		/// <summary>
		/// 将指定的字符串（它将二进制数据编码为 Base64 数字）转换为等效的 8 位无符号整数数组。
		/// </summary>
		/// <param name="input">要转换的字符串。</param>
		/// <returns>与 <paramref name="input"/> 等效的 8 位无符号整数数组。</returns>
		/// <exception cref="System.FormatException"><paramref name="input"/> 的长度（忽略空白字符）不是 0 或 4 的倍数。- 或 -<paramref name="input"/> 的格式无效。<paramref name="input"/> 包含一个非 base 64 字符、两个以上的填充字符或者在填充字符中包含非空白字符。</exception>
		[SecuritySafeCritical]
		public static byte[] FromBase64String(string input)
		{
			if (input == null)
				return null;

			return System.Convert.FromBase64String(input);
		}
		/// <summary>
		/// 将 8 位无符号整数数组的子集转换为用 Base64 数字编码的 Unicode 字符数组的等价子集。参数将子集指定为输入和输出数组中的偏移量和输入数组中要转换的元素数。
		/// </summary>
		/// <param name="input">8 位无符号整数的输入数组。</param>
		/// <param name="offsetIn"><paramref name="input"/> 内的一个位置。</param>
		/// <param name="length">要转换的 <paramref name="input"/> 的元素数。</param>
		/// <param name="output">Unicode 字符的输出数组。</param>
		/// <param name="offsetOut"><paramref name="output"/> 内的一个位置。</param>
		/// <returns>包含 <paramref name="output"/> 中的字节数的 32 位有符号整数。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="offsetIn"/>、<paramref name="offsetOut"/> 或 <paramref name="length"/> 为负。- 或 -<paramref name="offsetIn"/> 加上 <paramref name="length"/> 大于 <paramref name="input"/> 的长度。- 或 -<paramref name="offsetOut"/> 加上要返回的元素数大于 <paramref name="output"/> 的长度。</exception>
		public static int GetBase64CharArray(byte[] input, int offsetIn, int length, char[] output, int offsetOut)
		{
			if (input == null || output == null)
				return 0;

			if (length < offsetIn)
				length = input.Length;
			return System.Convert.ToBase64CharArray(input, offsetIn, length, output, offsetOut);
		}
		/// <summary>
		/// 将 8 位无符号整数数组的子集转换为用 Base64 数字编码的 Unicode 字符数组的等价子集。参数指定作为输入和输出数组中偏移量的子集、输入数组中要转换的元素数以及是否在输出数组中插入分行符。
		/// </summary>
		/// <param name="input">8 位无符号整数的输入数组。</param>
		/// <param name="offsetIn"><paramref name="input"/> 内的一个位置。</param>
		/// <param name="length">要转换的 <paramref name="input"/> 的元素数。</param>
		/// <param name="output">Unicode 字符的输出数组。</param>
		/// <param name="offsetOut"><paramref name="output"/> 内的一个位置。</param>
		/// <param name="options">如果每 76 个字符插入一个分行符，则使用 System.Base64FormattingOptions.InsertLineBreaks，如果不插入分行符，则使用 System.Base64FormattingOptions.None。</param>
		/// <returns>包含 <paramref name="output"/> 中的字节数的 32 位有符号整数。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="offsetIn"/>、<paramref name="offsetOut"/> 或 <paramref name="length"/> 为负。- 或 -<paramref name="offsetIn"/> 加上 <paramref name="length"/> 大于 <paramref name="input"/> 的长度。- 或 -<paramref name="offsetOut"/> 加上要返回的元素数大于 <paramref name="output"/> 的长度。</exception>
		/// <exception cref="System.ArgumentException"><paramref name="options"/> 不是有效的 System.Base64FormattingOptions 值。</exception>
		[SecuritySafeCritical]
		[ComVisible(false)]
		public static int GetBase64CharArray(byte[] input, int offsetIn, int length, char[] output, int offsetOut, Base64FormattingOptions options)
		{
			if (input == null || output == null)
				return 0;

			if (length < offsetIn)
				length = input.Length;
			return System.Convert.ToBase64CharArray(input, offsetIn, length, output, offsetOut, options);
		}
		/// <summary>
		/// 将 8 位无符号整数的数组转换为其用 Base64 数字编码的等效字符串表示形式。
		/// </summary>
		/// <param name="input">一个 8 位无符号整数数组。</param>
		/// <returns><paramref name="input"/> 的内容的字符串表示形式，以 Base64 表示。</returns>
		public static string GetBase64String(byte[] input)
		{
			if (input == null)
				return null;

			return System.Convert.ToBase64String(input);
		}
		/// <summary>
		/// 将 8 位无符号整数的数组转换为其用 Base64 数字编码的等效字符串表示形式。参数指定是否在返回值中插入分行符。
		/// </summary>
		/// <param name="input">一个 8 位无符号整数数组。</param>
		/// <param name="options">如果每 76 个字符插入一个分行符，则使用 System.Base64FormattingOptions.InsertLineBreaks，如果不插入分行符，则使用 System.Base64FormattingOptions.None。</param>
		/// <returns><paramref name="input"/> 中元素的字符串表示形式，以 Base64 表示。</returns>
		/// <exception cref="System.ArgumentException"><paramref name="options"/> 不是有效的 System.Base64FormattingOptions 值。</exception>
		[ComVisible(false)]
		public static string GetBase64String(byte[] input, Base64FormattingOptions options)
		{
			if (input == null)
				return null;

			return System.Convert.ToBase64String(input, options);
		}
		/// <summary>
		/// 将 8 位无符号整数数组的子集转换为其用 Base64 数字编码的等效字符串表示形式。参数将子集指定为输入数组中的偏移量和数组中要转换的元素数。
		/// </summary>
		/// <param name="input">一个 8 位无符号整数数组。</param>
		/// <param name="offset"><paramref name="input"/> 中的偏移量。</param>
		/// <param name="length">要转换的 <paramref name="input"/> 的元素数。</param>
		/// <returns><paramref name="input"/> 中从位置 <paramref name="offset"/> 开始的 <paramref name="length"/> 元素的字符串表示形式，以 Base64 表示。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="offset"/> 或 <paramref name="length"/> 为负。- 或 -<paramref name="offset"/> 加上 <paramref name="length"/> 大于 <paramref name="input"/> 的长度。</exception>
		public static string GetBase64String(byte[] input, int offset, int length)
		{
			if (input == null)
				return null;

			if (length < offset)
				length = input.Length;
			return System.Convert.ToBase64String(input, offset, length);
		}
		/// <summary>
		/// 将 8 位无符号整数数组的子集转换为其用 Base64 数字编码的等效字符串表示形式。参数指定作为输入数组中偏移量的子集、数组中要转换的元素数以及是否在返回值中插入分行符。
		/// </summary>
		/// <param name="input">一个 8 位无符号整数数组。</param>
		/// <param name="offset"><paramref name="input"/> 中的偏移量。</param>
		/// <param name="length">要转换的 <paramref name="input"/> 的元素数。</param>
		/// <param name="options">如果每 76 个字符插入一个分行符，则使用 System.Base64FormattingOptions.InsertLineBreaks，如果不插入分行符，则使用 System.Base64FormattingOptions.None。</param>
		/// <returns><paramref name="input"/> 中从位置 <paramref name="offset"/> 开始的 <paramref name="length"/> 元素的字符串表示形式，以 Base64 表示。</returns>
		/// <exception cref="System.ArgumentOutOfRangeException"><paramref name="offset"/> 或 <paramref name="length"/> 为负。- 或 -<paramref name="offset"/> 加上 <paramref name="length"/> 大于 <paramref name="input"/> 的长度。</exception>
		/// <exception cref="System.ArgumentException"><paramref name="options"/> 不是有效的 System.Base64FormattingOptions 值。</exception>
		[ComVisible(false)]
		[SecuritySafeCritical]
		public static string GetBase64String(byte[] input, int offset, int length, Base64FormattingOptions options)
		{
			if (input == null)
				return null;

			if (length < offset)
				length = input.Length;
			return System.Convert.ToBase64String(input, offset, length, options);
		}
	}
}
